Skip to main content

Others

JavaScript Error Handling​

Basic Error Handling​

Use try…catch to handle errors that occur while executing code.

try {
const response = await fetch(`/api/users/${userId}`)
return await response.json()
} catch (error) {
console.log(error.message)
}

The catch block receives the thrown error object, allowing you to inspect properties such as message or name.

Creating Custom Errors​

Custom error classes make it easier to identify and handle specific types of errors.

class ValidationError extends Error {
constructor(message) {
super(message)
this.name = 'ValidationError'
}
}

class NetworkError extends Error {
constructor(message, statusCode) {
super(message)
this.name = 'NetworkError'
this.statusCode = statusCode
}
}

Usage:

throw new ValidationError('Invalid email')

A Better Custom Error Pattern​

Instead of manually setting the name property in every error class, create a common base class.

class AppError extends Error {
constructor(message, options) {
super(message, options)
this.name = this.constructor.name
}
}

class ValidationError extends AppError {}
class DatabaseError extends AppError {}
class NetworkError extends AppError {}

Now every subclass automatically gets the correct error name.

throw new ValidationError('Invalid email')

// error.name === "ValidationError"

Handling Different Error Types​

Use instanceof to handle different errors appropriately.

try {
await saveUser(userData)
} catch (error) {
if (error instanceof ValidationError) {
// Show validation message to the user
showFieldErrors(error.fields)

} else if (error instanceof NetworkError) {
// Network issue - maybe retry
showRetryButton()

} else {
// Unknown error
console.error('Unexpected error:', error)
showGenericError()
}
}

Always Check response.ok with fetch​

  • A common mistake is assuming that fetch() throws an error for HTTP status codes like 404 or 500.
  • It doesn't.
    • fetch() only throws for network-related failures. For HTTP errors, you must check response.ok yourself.
  • Incorrect
try {
const response = await fetch('/api/users/999')
const user = await response.json()
} catch (error) {
// Only catches network errors
}
  • Correct
try {
const response = await fetch('/api/users/999')

if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`)
}

const user = await response.json()
} catch (error) {
// Catches both network and HTTP errors
console.error('Request failed:', error.message)
}

JavaScript Regular Expressions (RegExp)​

  • Regular expressions (RegExp) are patterns used to search, validate, extract, and replace text.

test() Vs match()​

These are two of the most commonly used regular expression methods.

  • test()
    • Returns a boolean indicating whether the pattern matches.
const emailPattern = /\S+@\S+\.\S+/

console.log(emailPattern.test('user@example.com')) // true
console.log(emailPattern.test('userexample.com')) // false
  • match()
    • Returns an array containing the matched text (or null if no match is found).
    • Using the g (global) flag returns all matches instead of only the first.
const text = 'Order IDs: 123, 456, 789'

console.log(text.match(/\d+/g))
// ["123", "456", "789"]

search()​

  • Returns the index where the first match starts.
  • If no match is found, it returns -1.
const text = 'Hello World'

console.log(text.search(/World/)) // 6
console.log(text.search(/xyz/)) // -1

replace()​

  • Replace matching text with another value.
  • Using the g flag replaces all occurrences.
console.log('hello world'.replace(/o/g, '0'))

// "hell0 w0rld"

split()​

  • Regular expressions can also be used with split().
// The pattern removes optional whitespace around commas.
const items = 'a, b,c , d'.split(/\s*,\s*/)

console.log(items)

// ["a", "b", "c", "d"]

Named Capture Groups​

  • Named capture groups make matched values easier to access.
  • Use the following syntax:
(?<name>pattern)
  • Example:
const datePattern = /(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/

const match = '12-25-2024'.match(datePattern)

console.log(match.groups.month) // "12"
console.log(match.groups.day) // "25"
console.log(match.groups.year) // "2024"

Greedy Vs Lazy Matching​

  • By default, quantifiers are greedy. They match as much text as possible.
  • Adding ? makes a quantifier lazy, meaning it matches as little text as possible.
  • Example:
const html = '<div>Hello</div><div>World</div>'

Greedy​

Matches everything between the first <div> and the last </div>.

console.log(html.match(/<div>.*<\/div>/)[0])

// "<div>Hello</div><div>World</div>"

Lazy​

Stops at the first closing </div>.

console.log(html.match(/<div>.*?<\/div>/)[0])

// "<div>Hello</div>"